/**********************************************************************

   Audacity: A Digital Audio Editor
   Audacity(R) is copyright (c) 1999-2016 Audacity Team.
   License: GPL v2 or later.  See License.txt.

   BassTrebleBase.h (two shelf filters)
   Steve Daulton

**********************************************************************/
#pragma once

#include "PerTrackEffect.h"
#include "SettingsVisitor.h"

// Used to communicate the type of the filter.
enum kShelfType
{
    kBass,
    kTreble
};

class BassTrebleState
{
public:
    float samplerate;
    double treble;
    double bass;
    double gain;
    double slope, hzBass, hzTreble;
    double a0Bass, a1Bass, a2Bass, b0Bass, b1Bass, b2Bass;
    double a0Treble, a1Treble, a2Treble, b0Treble, b1Treble, b2Treble;
    double xn1Bass, xn2Bass, yn1Bass, yn2Bass;
    double xn1Treble, xn2Treble, yn1Treble, yn2Treble;
};

struct BassTrebleSettings
{
    static constexpr double bassDefault = 0.0;
    static constexpr double trebleDefault = 0.0;
    static constexpr double gainDefault = 0.0;
    static constexpr bool linkDefault = false;

    double mBass { bassDefault };
    double mTreble { trebleDefault };
    double mGain { gainDefault };
    bool mLink { linkDefault };
};

class BUILTIN_EFFECTS_API BassTrebleBase : public EffectWithSettings<BassTrebleSettings, PerTrackEffect>
{
public:
    static const ComponentInterfaceSymbol Symbol;

    BassTrebleBase();
    virtual ~BassTrebleBase();

    // ComponentInterface implementation

    ComponentInterfaceSymbol GetSymbol() const override;
    TranslatableString GetDescription() const override;
    ManualPageID ManualPage() const override;

    // EffectDefinitionInterface implementation

    EffectType GetType() const override;
    RealtimeSince RealtimeSupport() const override;

    // Effect Implementation

    bool CheckWhetherSkipEffect(const EffectSettings& settings) const override;

    struct BUILTIN_EFFECTS_API Instance : public PerTrackEffect::Instance, public EffectInstanceWithBlockSize
    {
        explicit Instance(const PerTrackEffect& effect)
            : PerTrackEffect::Instance {effect}
        {
        }

        bool ProcessInitialize(
            EffectSettings& settings, double sampleRate, ChannelNames chanMap) override;

        size_t ProcessBlock(
            EffectSettings& settings, const float* const* inBlock, float* const* outBlock, size_t blockLen) override;

        bool RealtimeInitialize(EffectSettings& settings, double, size_t audioThreadBufferSize) override;

        bool RealtimeAddProcessor(
            EffectSettings& settings, EffectOutputs* pOutputs, unsigned numChannels, float sampleRate) override;

        bool RealtimeFinalize(EffectSettings& settings) noexcept override;

        size_t RealtimeProcess(
            size_t group, EffectSettings& settings, const float* const* inbuf, float* const* outbuf, size_t numSamples) override;

        unsigned GetAudioInCount() const override;
        unsigned GetAudioOutCount() const override;

        static void InstanceInit(
            EffectSettings& settings, BassTrebleState& data, float sampleRate);

        static size_t InstanceProcess(
            EffectSettings& settings, BassTrebleState& data, const float* const* inBlock, float* const* outBlock, size_t blockLen);

        static void Coefficients(
            double hz, double slope, double gain, double samplerate, int type, double& a0, double& a1, double& a2, double& b0, double& b1,
            double& b2);

        static float DoFilter(BassTrebleState& data, float in);

        BassTrebleState mState;
        std::vector<BassTrebleBase::Instance> mSlaves;
    };

protected:
    const EffectParameterMethods& Parameters() const override;

    static constexpr EffectParameter Bass { &BassTrebleSettings::mBass,
                                            L"Bass",
                                            BassTrebleSettings::bassDefault,
                                            -30.0,
                                            30.0,
                                            1 };

    static constexpr EffectParameter Treble { &BassTrebleSettings::mTreble,
                                              L"Treble",
                                              BassTrebleSettings::trebleDefault,
                                              -30.0,
                                              30.0,
                                              1 };

    static constexpr EffectParameter Gain { &BassTrebleSettings::mGain,
                                            L"Gain",
                                            BassTrebleSettings::gainDefault,
                                            -30.0,
                                            30.0,
                                            1 };

    static constexpr EffectParameter Link { &BassTrebleSettings::mLink,
                                            L"Link Sliders",
                                            BassTrebleSettings::linkDefault,
                                            false,
                                            true,
                                            1 };
};
